package uz.rt.dicom.io;

import uz.rt.dicom.dictionary.DicomDictionary;
import uz.rt.dicom.dictionary.DictionaryTag;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * A dicom dictionary reader which reads and parses a file contain a complete dicom dictionary.
 * The reading functionality currently supports the DCMTK dicom dictionary but can be extended in the future with any
 * other type of dicom dictionary.
 */
public class DictionaryReader
{
// ------------------------------ FIELDS ------------------------------

    /** DictionaryReader logger */
    private static final Logger logger = Logger.getLogger(DictionaryReader.class.getName());
    /** File name */
    private String fileName;

// --------------------------- CONSTRUCTORS ---------------------------

    /**
     * Constructor that set the filename of the dicom dictionary file that needs to be read.
     *
     * @param fileName Dicom dictionary file that needs to be read.
     */
    public DictionaryReader(String fileName)
    {
        setFileName(fileName);
    }

// --------------------- GETTER / SETTER METHODS ---------------------

    /**
     * Get the filename of the dicom dictionary file.
     *
     * @return Filename of the dicom dictionary file.
     */
    public String getFileName()
    {
        return fileName;
    }

    /**
     * Set the filename of the dicom dictionary file.
     *
     * @param fileName Filename of the dicom dictionary file.
     */
    void setFileName(String fileName)
    {
        this.fileName = fileName;
    }

// -------------------------- OTHER METHODS --------------------------

    /**
     * Read a dicom dictionary file based on the currently supported DicType.
     *
     * @param dicType Dicom dictionary type
     * @throws IOException If an IO error occurs.
     */
    public void read(DicType dicType) throws IOException
    {
        if (dicType == DicType.DCMTK)
            readDcmtkDic();
        else
            throw new DicomIOException("Dictionary type is not supported");
    }

    /**
     * Reads a DCMTK dicom dictionary file. The function ignores:
     * <ul>
     * <li>Lines starting with #</li>
     * <li>Dicom tags containing a - in their group or element</li>
     * <li>It doesn't check if a tag is retired</li>
     * </ul>
     *
     * @throws IOException If an IO error occurs.
     */
    private synchronized void readDcmtkDic() throws IOException
    {
        BufferedReader reader = new BufferedReader(new FileReader(fileName));
        String line;
        while ((line = reader.readLine()) != null)
        {
            if (line.startsWith("#")) continue;
            if (!line.startsWith("(")) continue;
            String[] list = line.split("\t");
            // dicom tag
            list[0] = list[0].replace("(", "");
            list[0] = list[0].replace(")", "");
            String[] tag = list[0].trim().split(",");
            if (tag.length != 2)
                throw new DicomIOException("Expected a dicom tag formatted as: (group,element)");
            if (tag[0].contains("-")) continue; // not yet supported
            if (tag[1].contains("-")) continue;
            // # Tag           VR      Name                    VM      Version
            try
            {
                String name = list[2].trim();
                int group = Integer.parseInt(tag[0], 16);
                int element = Integer.parseInt(tag[1], 16);
                String vr = list[1].trim();
                if (vr.equals("up") || vr.equals("xs") || vr.equals("ox"))
                {
                    logger.log(Level.WARNING, "Found an unknown value representation " + vr.toUpperCase() + ", " +
                            "moving on to next dictionary item.");
                    continue;
                }
                String vm = list[3].trim();
                DictionaryTag dictionaryTag = new DictionaryTag(name, group, element, vr.toUpperCase(), vm);
                DicomDictionary.getInstance().addTag(dictionaryTag);
            }
            catch (Exception e)
            {
                throw new DicomIOException(e.getMessage());
            }
        }
        reader.close();
    }

// -------------------------- ENUMERATIONS --------------------------

    /** Dictionary types that the reader can read and parse. */
    public enum DicType
    {
        /** DCMTK dicom dictionary */
        DCMTK
    }
}
